#include <iostream>
#include <sstream>
#include "EditorGameState.h"
#include "TinyXML2.h"
#include "Library.h"
#include "SceneGraph.h"
#include "ModelNode.h"
#include "TransformationNode.h"
#include "OrientationComponent.h"
#include "GraphicalComponent.h"
#include "SelectableComponent.h"
#include "RigidBodyComponent.h"
#include "BoundingSphere.h"
#include "TriangleMesh.h"
#include "LightNode.h"
#include "IRenderer.h"

bool EditorGameState::UnloadNode( INode* node, tinyxml2::XMLPrinter& printer )
{
	if (node->Type() == HashedString("GUINode"))
	{
		return true;
	}
	printer.OpenElement("Node");
	if (node->Type() == HashedString("TransformationNode"))
	{	
		Entity::Map_t::iterator it;
		for (it = m_entities.begin(); it != m_entities.end(); ++it)
		{
			HashedString name(it->first);
			Entity* entity = it->second;
			OrientationComponent* component = (OrientationComponent*)(entity->FindComponent(OrientationComponent::type));
			if (component)
			{
				if ((void*)(component->getTransformNode()) == (void*)node)
				{
					printer.PushAttribute("Type", "Entity");
					printer.PushAttribute("Name", name.getString().c_str());
					printer.PushAttribute("Component", OrientationComponent::type.getString().c_str());
					break;
				}
			}
		}
		if (it == m_entities.end())
		{
			printer.PushAttribute("Type", node->Type().getString().c_str());
			TransformationNode* transform = (TransformationNode*)node;

			Maths::Vector3D& position = ((ValueTrigger<Maths::Vector3D>*)(TriggerBase*)transform->getPosition())->getObject();
			Maths::Quaternion& rotation = ((ValueTrigger<Maths::Quaternion>*)(TriggerBase*)transform->getRotation())->getObject();
			
			printer.OpenElement("Position");
			printer.PushText(position.X());
			printer.PushText(" ");
			printer.PushText(position.Y());
			printer.PushText(" ");
			printer.PushText(position.Z());
			printer.CloseElement();

			printer.OpenElement("Rotation");
			printer.PushText(rotation.X());
			printer.PushText(" ");
			printer.PushText(rotation.Y());
			printer.PushText(" ");
			printer.PushText(rotation.Z());
			printer.PushText(" ");
			printer.PushText(rotation.W());
			printer.CloseElement();
		}
	}
	else if (node->Type() == HashedString("ModelNode"))
	{
		ModelNode* model = (ModelNode*)((INode*)node);
		Entity::Map_t::iterator it;
		for (it = m_entities.begin(); it != m_entities.end(); ++it)
		{
			HashedString name(it->first);
			Entity* entity = it->second;
			GraphicalComponent* component = (GraphicalComponent*)(entity->FindComponent(GraphicalComponent::type));
			if (component)
			{
				if ((void*)(component->getNode()) == (void*)node)
				{
					printer.PushAttribute("Type", "Entity");
					printer.PushAttribute("Name", name.getString().c_str());
					printer.PushAttribute("Component", GraphicalComponent::type.getString().c_str());
					break;
				}
			}
		}
		
		if (it == m_entities.end())
		{
			printer.PushAttribute("Type", "ModelNode");
			Pointer<IResource> resource;
			CopyPointer(model->getModelInstance()->getModel(), resource);
			HashedString modelName(Library::getSingleton().getResourceName(Model::type, resource));
			printer.PushAttribute("Model", modelName.getString().c_str());
		}
	}
	else if (node->Type() == HashedString("LightNode"))
	{
		LightNode* lightNode = (LightNode*)node;
		Light& light = lightNode->getLight();
		
		printer.PushAttribute("Type", node->Type().getString().c_str());
		printer.OpenElement("Position");
		for (int i = 0; i <3; ++i)
		{
			printer.PushText(light.m_Position[i]);
			printer.PushText(" ");
		}
		printer.PushText(light.m_Position[3]);
		printer.CloseElement();

		printer.OpenElement("Ambient");
		for (int i = 0; i < 3; ++i)
		{
			printer.PushText(light.m_Ambient[i]);
			printer.PushText(" ");
		}
		printer.PushText(light.m_Ambient[3]);
		printer.CloseElement();

		printer.OpenElement("Diffuse");
		for (int i = 0; i < 3; ++i)
		{
			printer.PushText(light.m_Diffuse[i]);
			printer.PushText(" ");
		}
		printer.PushText(light.m_Diffuse[3]);
		printer.CloseElement();

		printer.OpenElement("Specular");
		for (int i = 0; i < 3; ++i)
		{
			printer.PushText(light.m_Specular[i]);
			printer.PushText(" ");
		}
		printer.PushText(light.m_Specular[3]);
		printer.CloseElement();
		printer.OpenElement("SpotDirection");
		for (int i = 0; i < 2; ++i)
		{
			printer.PushText(light.m_SpotDirection[i]);
			printer.PushText(" ");
		}
		printer.PushText(light.m_SpotDirection[2]);
		printer.CloseElement();
		printer.OpenElement("SpotExponent");
		printer.PushText(light.m_SpotExponent);
		printer.CloseElement();
		printer.OpenElement("SpotCutOff");
		printer.PushText(light.m_SpotCutOff);
		printer.CloseElement();
		printer.OpenElement("ConstAttenuation");
		printer.PushText(light.m_ConstAttenuation);
		printer.CloseElement();
		printer.OpenElement("LinearAttenuation");
		printer.PushText(light.m_LinearAttenuation);
		printer.CloseElement();
		printer.OpenElement("QuadraticAttenuation");
		printer.PushText(light.m_QuadraticAttenuation);
		printer.CloseElement();
	}
	else if (node->Type() == HashedString("Root"))
	{
		printer.PushAttribute("Type", "Root");
	}
	else if (node->Type() == HashedString("CameraNode"))
	{
		CameraNode* camera = (CameraNode*)node;
		printer.PushAttribute("Type", "CameraNode");
		printer.PushAttribute("IsPerspective", camera->IsProjection());
		Maths::Vector3D position(camera->Position());
		Maths::Vector3D rotation(camera->Rotation());
		printer.OpenElement("Position");
		printer.PushText(position.X());
		printer.PushText(" ");
		printer.PushText(position.Y());
		printer.PushText(" ");
		printer.PushText(position.Z());
		printer.CloseElement();

		printer.OpenElement("Rotation");
		printer.PushText(rotation.X());
		printer.PushText(" ");
		printer.PushText(rotation.Y());
		printer.PushText(" ");
		printer.PushText(rotation.Z());
		printer.CloseElement();

		printer.OpenElement("Near");
		printer.PushText(camera->Near());
		printer.CloseElement();
		printer.OpenElement("Far");
		printer.PushText(camera->Far());
		printer.CloseElement();
		if (camera->IsProjection())
		{
			printer.OpenElement("Fovy");
			printer.PushText(camera->Fovy());
			printer.CloseElement();
		} else
		{
			printer.OpenElement("Left");
			printer.PushText(camera->Left());
			printer.CloseElement();
			printer.OpenElement("Right");
			printer.PushText(camera->Right());
			printer.CloseElement();
			printer.OpenElement("Top");
			printer.PushText(camera->Top());
			printer.CloseElement();
			printer.OpenElement("Bottom");
			printer.PushText(camera->Bottom());
			printer.CloseElement();
		}
	}
	for (INode::Vector_t::iterator it = node->getChildren().begin(); it != node->getChildren().end(); ++it)
	{
		UnloadNode((*it), printer);
	}
	printer.CloseElement();
	return true;
}
bool EditorGameState::UnloadComponent( const IComponent::Pair_t& componentPair, tinyxml2::XMLPrinter& printer )
{
	
	const HashedString& type (componentPair.first);
	IComponent* component = (componentPair.second);
	
	printer.OpenElement("Component");
	printer.PushAttribute("Type", type.getString().c_str());

	component->ToXML(printer);

	printer.CloseElement();
	return true;
}
bool EditorGameState::UnloadEntity( const Entity::Pair_t& entityPair, tinyxml2::XMLPrinter& printer )
{
	const HashedString& name(entityPair.first);
	Entity* entity = (entityPair.second);
	printer.OpenElement("Entity");
	printer.PushAttribute("Name", name.getString().c_str());
	printer.PushAttribute("Components", entity->Components().size());

	for (IComponent::Map_t::reverse_iterator it = entity->Components().rbegin(); it != entity->Components().rend(); ++it)
	{
		UnloadComponent(*it, printer);
	}
	printer.CloseElement();
	return true;
}
bool EditorGameState::UnloadResource( const Library::ResourcesPair_t& resource, tinyxml2::XMLPrinter& printer)
{
	HashedString type(resource.first);
	const IResource::Map_t& resources = resource.second;

	for (IResource::Map_t::const_iterator it = resources.begin(); it != resources.end(); ++it)
	{
		HashedString name(it->first);

		printer.OpenElement("Resource");
		printer.PushAttribute("Type", type.getString().c_str());
		printer.PushAttribute("Name", name.getString().c_str());

		IResource* resourcePtr = it->second;
		resourcePtr->ToXML(printer);
		
		printer.CloseElement();
	}

	return true;
}
bool EditorGameState::UnloadGameState( std::string filename)
{
	FILE* fp;

	fopen_s(&fp, filename.c_str(), "w");

	if (fp==NULL)
		return false;

	tinyxml2::XMLPrinter printer(fp);

	
	printer.OpenElement("State");

	// Textures
	printer.OpenElement("TextureList");
	printer.PushAttribute("Count", m_textureStrings.size());

	for (std::vector<std::string>::iterator it = m_textureStrings.begin(); it != m_textureStrings.end(); ++it)
	{
		printer.OpenElement("Texture");
		printer.PushAttribute("Filename", (*it).c_str());
		printer.CloseElement();
	}

	printer.CloseElement();

	// Resource List
	printer.OpenElement("ResourceList");
	printer.PushAttribute("Count", Library::getSingleton().ResourceCount());

	for (Library::ResourcesMap_t::iterator it = Library::getSingleton().getResources().begin(); it != Library::getSingleton().getResources().end(); ++it)
	{
		UnloadResource(*it, printer);
	}

	printer.CloseElement();

	// Write entities
	// Entity Header
	printer.OpenElement("EntityList");
	printer.PushAttribute("Count", m_entityCounter);

	// Entities
	for (Entity::Map_t::iterator it = m_entities.begin(); it != m_entities.end(); ++it)
	{
		const Entity::Pair_t& pair(*it);
		UnloadEntity(pair, printer);
	}

	printer.CloseElement();

	// SceneGraph

	printer.OpenElement("SceneGraph");

	UnloadNode(SceneGraph::getSingletonPtr(), printer);
	
	printer.CloseElement();
	printer.CloseElement();

	fclose(fp);

	return true;
}

bool EditorGameState::LoadModel(tinyxml2::XMLElement* element)
{
	HashedString name(element->Attribute("Name"));
	
	cmbModelName->AddItem(name.getString());

	tinyxml2::XMLElement* meshes = element->FirstChildElement("Meshes");
	const unsigned int count = meshes->UnsignedAttribute("Count");
	tinyxml2::XMLElement* meshxml = meshes->FirstChildElement("Mesh");
	unsigned int counter = 0;

	Pointer<Model> model = new Model();
	Pointer<Mesh> mesh;
	

	while (counter < count)
	{
		mesh = new Mesh();
#pragma region Material
		Material& mat = mesh->getMaterial();
		tinyxml2::XMLElement* matXML = meshxml->FirstChildElement("Material");
		// uniforms
		{
			std::stringstream attrib(std::string(matXML->Attribute("Ambient")));
			attrib >> mat.m_ambient[0] >> mat.m_ambient[1] >> mat.m_ambient[2] >> mat.m_ambient[3];
		}
		{
			std::stringstream attrib(std::string(matXML->Attribute("Diffuse")));
			attrib >> mat.m_diffuse[0] >> mat.m_diffuse[1] >> mat.m_diffuse[2] >> mat.m_diffuse[3];
		}
		{
			std::stringstream attrib(std::string(matXML->Attribute("Emmisive")));
			attrib >> mat.m_emmisive[0] >> mat.m_emmisive[1] >> mat.m_emmisive[2] >> mat.m_emmisive[3];
		}
		{
			std::stringstream attrib(std::string(matXML->Attribute("Specular")));
			attrib >> mat.m_specular[0] >> mat.m_specular[1] >> mat.m_specular[2] >> mat.m_specular[3];
		}
		mat.m_shininess = matXML->FloatAttribute("Shininess");
		mat.m_shader = HashedString(matXML->Attribute("Shader"));
		
		for (tinyxml2::XMLElement* texture = matXML->FirstChildElement("Texture"); texture != NULL; texture = texture->NextSiblingElement("Texture"))
		{
			mat.m_textures.push_back(HashedString(texture->Attribute("Name")));
		}

#pragma endregion

#pragma region VerticeContainer
		Pointer<IVertexContainer>& vertices = mesh->getVertexContainer();
		tinyxml2::XMLElement* vertexContainer = meshxml->FirstChildElement("VertexContainer");
		
		bool IsVBO = vertexContainer->BoolAttribute("VBO");
		bool IsIBO = vertexContainer->BoolAttribute("IBO");

		tinyxml2::XMLElement* declaration = vertexContainer->FirstChildElement("Declaration");
		unsigned int size = declaration->UnsignedAttribute("Size");

		VertexType::Vector_t params;
		for (tinyxml2::XMLElement* parameter = declaration->FirstChildElement("Parameter"); parameter != NULL; parameter = parameter->NextSiblingElement())
			params.push_back(VertexType(parameter->UnsignedAttribute("Offset"), parameter->UnsignedAttribute("Size"),(VertexParameter)(parameter->UnsignedAttribute("Parameter"))));
		
		tinyxml2::XMLElement* verticeXML = vertexContainer->FirstChildElement("Vertices");
		vertices = new IVertexContainer(VertexDeclaration(params));

		vertices->resize(verticeXML->UnsignedAttribute("Count"));
		unsigned char* ptr = (unsigned char*)(vertices->getVertexPointer());

		{
			std::stringstream ss(std::string(verticeXML->FirstChild()->ToText()->Value()), std::stringstream::in | std::stringstream::out);
			for (unsigned int i = 0; i < vertices->getVerticeCount() * size; ++i)
			{
				unsigned int value;
				ss >> value;
				*ptr = value;;
				++ptr;
			}
		}

#pragma endregion

#pragma region Indices
		tinyxml2::XMLElement* indicesXML = vertexContainer->FirstChildElement("Indices");
		vertices->getIndices().resize(indicesXML->UnsignedAttribute("Count"));
		if (vertices->getIndices().size() > 0)
		{
			std::stringstream ss(std::string(indicesXML->FirstChild()->ToText()->Value()), std::stringstream::in | std::stringstream::out);
			for (unsigned int i = 0; i < vertices->getIndiceCount(); ++i)
			{
				unsigned short value = 0;
				ss >> value;
				((unsigned short*)vertices->getIndexPointer())[i] = value;
			}
		}
#pragma endregion

		meshxml = meshxml->NextSiblingElement();
		model->getMeshes().push_back(mesh);
		++counter;
	}

	Pointer<IResource> iresource;
	CopyPointer(model, iresource);
	Library::getSingleton().AddResource(name, iresource);
	return true;
}
bool EditorGameState::LoadResource(tinyxml2::XMLElement* element)
{
	HashedString type(element->Attribute("Type"));
	if (type == Model::type)
	{
		LoadModel(element);
	}
	return true;
}
bool EditorGameState::LoadResources(tinyxml2::XMLElement* element)
{
	const unsigned int count = element->UnsignedAttribute("Count");
	unsigned int counter = 0;
	
	tinyxml2::XMLElement* resource = element->FirstChildElement("Resource");
	while (counter < count)
	{
		LoadResource(resource);
		
		resource = resource->NextSiblingElement("Resource");
		++counter;
	}
	
	return true;
}
bool EditorGameState::LoadEntities(tinyxml2::XMLElement* element)
{
	unsigned int count = element->UnsignedAttribute("Count");
	for (tinyxml2::XMLElement* entity = element->FirstChildElement("Entity"); entity != NULL; entity = entity->NextSiblingElement())
		LoadEntity(entity);
	return true;
}
bool EditorGameState::LoadEntity(tinyxml2::XMLElement* element)
{
	HashedString entityName(element->Attribute("Name"));

	Pointer<Entity> entity = new Entity();
	
	SelectableComponent* selectable = 0;
	RigidBodyComponent* rigidbody = 0;
	GraphicalComponent* graphic = 0;
	OrientationComponent* orientation = 0;

	for (tinyxml2::XMLElement* component = element->FirstChildElement("Component"); component != NULL; component = component->NextSiblingElement("Component"))
	{
		HashedString type(component->Attribute("Type"));
		if (type == GraphicalComponent::type)
		{
			HashedString modelName(component->FirstChildElement("Model")->Attribute("Name"));
			Pointer<IResource> resource = Library::getSingleton().getResource(Model::type, modelName);
			if (resource.isValid())
			{
				Pointer<Model> model;
				CopyPointer(resource, model);
				Pointer<IComponent> comp = graphic = new GraphicalComponent(entity,model);
				entity->RegisterComponent(GraphicalComponent::type, comp);
			}
		} else if (type == OrientationComponent::type)
		{
			orientation = new OrientationComponent(entity);
			tinyxml2::XMLElement* posXML = component->FirstChildElement("Position");
			tinyxml2::XMLElement* rotXML = component->FirstChildElement("Rotation");
			Maths::Vector3D position, rotation;
			{
				std::stringstream attrib(std::string(posXML->Attribute("Vector")));
				attrib >> position.X() >> position.Y() >> position.Z();
			}
			{
				std::stringstream attrib(std::string(rotXML->Attribute("Vector")));
				attrib >> rotation.X() >> rotation.Y() >> rotation.Z();
			}
			orientation->getPosition() = position;
			orientation->getRotation() = Maths::Quaternion(rotation);

			if (rigidbody)
			{
				rigidbody->getPosition() = new DoubleValueTrigger<Maths::Vector3D>(&orientation->getPosition(), &selectable->getBody()->getPosition());
				rigidbody->getBody()->AddShape(Pointer<IShape>(new BoundingSphere(1.0f)));
				m_selectables->AddRigidBody(rigidbody->getBody());
			}
			if (selectable)
			{
				selectable->getPosition() = new DoubleValueTrigger<Maths::Vector3D>(&orientation->getPosition(), &selectable->getBody()->getPosition());
				selectable->getBody()->AddShape(Pointer<IShape>(new BoundingSphere(1.0f)));
				m_selectables->AddRigidBody(selectable->getBody());
			}

			entity->RegisterComponent(OrientationComponent::type, Pointer<IComponent>(orientation));
		} else if (type == SelectableComponent::type)
		{
			selectable = new SelectableComponent(Pointer<RigidBody>(new RigidBody(1.0f, entity)), entity);;
			for (tinyxml2::XMLElement* shape = component->FirstChildElement("Shape"); shape != NULL; shape = shape->NextSiblingElement("Shape"))
			{
				HashedString shapeType(shape->Attribute("Type"));
				if (shapeType == BoundingSphere::type)
				{
					float radius;
					Maths::Vector3D offset;
					{
						std::stringstream attrib(std::string(shape->Attribute("Offset")));
						attrib >> offset.X() >> offset.Y() >> offset.Z();
					}
					{
						std::stringstream attrib(std::string(shape->Attribute("Detail")));
						attrib >> radius;
					}
					Pointer<IShape> ishape = new BoundingSphere(radius);
					ishape->setOffset(offset, Maths::Quaternion());
					selectable->getBody()->AddShape(ishape);
				} else if (shapeType == TriangleMesh::type && graphic)
				{
					ModelNode* modelNode = (ModelNode*)((INode*)graphic->getNode());
					Model* model = modelNode->getModelInstance()->getModel();
					Mesh::Vector_t& meshes = model->getMeshes();
					
					Pointer<IShape> mesh;
					for (Mesh::Vector_t::iterator it = meshes.begin(); it != meshes.end(); ++it)
					{
						unsigned int offset, size, vertSize = (*it)->getVertexContainer()->getVertexDeclaration().m_vertexSize;
#pragma region FIND_ENUMPOSITION
						{
							const VertexType::Vector_t& params = (*it)->getVertexContainer()->getVertexDeclaration().m_parameters;
							unsigned int paramSize = params.size();

							for (int i = 0; i < paramSize; ++i)
							{
								if (params[i].m_parameter == enumPosition)
								{
									offset = params[i].m_offset;
									size = params[i].m_size;
									break;
								}
							}
						}
#pragma endregion

						std::vector<float> verts;

						unsigned char* ptr = (unsigned char*)((*it)->getVertexContainer()->getVertexPointer()) + offset;
						unsigned int count = (*it)->getVertexContainer()->getVerticeCount();

						for (int i = 0; i < count; ++i)		// for each vertex
						{
							for (int j = 0; j < size; ++j)
								verts.push_back(*(((float*)ptr) + j));
							ptr += vertSize;
						}

						mesh = new TriangleMesh(&verts[0], count/3);
						selectable->getBody()->setMass(0.0f);
						selectable->getBody()->AddShape(mesh);
					}
				}
			}
			
			if (orientation)
			{
				selectable->getPosition() = new DoubleValueTrigger<Maths::Vector3D>(&orientation->getPosition(), &selectable->getBody()->getPosition());
				selectable->getBody()->AddShape(Pointer<IShape>(new BoundingSphere(1.0f)));
				m_selectables->AddRigidBody(selectable->getBody());
			}
			entity->RegisterComponent(SelectableComponent::type, Pointer<IComponent>(selectable));
		} else if (type == RigidBodyComponent::type)
		{
			RigidBodyComponent* rigidbody = new RigidBodyComponent(entity);
			for (tinyxml2::XMLElement* shape = component->FirstChildElement("Shape"); shape != NULL; shape = shape->NextSiblingElement("Shape"))
			{
				HashedString shapeType(shape->Attribute("Type"));
				if (shapeType == BoundingSphere::type)
				{
					float radius;
					Maths::Vector3D offset;
					{
						std::stringstream attrib(std::string(shape->Attribute("Offset")));
						attrib >> offset.X() >> offset.Y() >> offset.Z();
					}
					{
						std::stringstream attrib(std::string(shape->Attribute("Detail")));
						attrib >> radius;
					}
					Pointer<IShape> ishape = new BoundingSphere(radius);
					ishape->setOffset(offset, Maths::Quaternion());
					rigidbody->getBody()->AddShape(ishape);
				} else if (shapeType == TriangleMesh::type)
				{

				}
			}
			
			if (orientation)
			{
				rigidbody->getPosition() = new DoubleValueTrigger<Maths::Vector3D>(&orientation->getPosition(), &selectable->getBody()->getPosition());
				rigidbody->getBody()->AddShape(Pointer<IShape>(new BoundingSphere(1.0f)));
				m_selectables->AddRigidBody(rigidbody->getBody());
			}
			entity->RegisterComponent(RigidBodyComponent::type, Pointer<IComponent>(rigidbody));
		}
	}
	m_entities.insert(Entity::Pair_t(entityName, entity));
	return true;
}

bool EditorGameState::LoadSceneGraph(tinyxml2::XMLElement* element)
{
	for (INode::Vector_t::iterator it = SceneGraph::getSingleton().getChildren().begin(); it != SceneGraph::getSingleton().getChildren().end();)
	{
		if ((*it)->Type() != HashedString("GUINode"))
		{
			(*it)->Remove();
			it = SceneGraph::getSingleton().getChildren().begin();
		} else
		{
			++it;
		}
	}
		
	for (tinyxml2::XMLElement* node = element->FirstChildElement("Node"); node != NULL; node = node->NextSiblingElement("Node"))
	{
		LoadNode(0, node);
	}
	return true;
}
bool EditorGameState::LoadNode(INode* workingNode, tinyxml2::XMLElement* element)
{
	std::string type(element->Attribute("Type"));
	INode* thisNode;
	if (type == "Root")
	{
		thisNode = SceneGraph::getSingletonPtr();
	} else if (type == "CameraNode")
	{	
		CameraNode* camera;
		thisNode = camera = new CameraNode();

		Pointer<INode> _cameraNode(thisNode);
		CopyPointer(_cameraNode, m_cameraNode);
		workingNode->Push_Back(_cameraNode);
		
		bool isPerspective = element->BoolAttribute("IsPerspective");

		tinyxml2::XMLElement* posXML = element->FirstChildElement("Position");
		tinyxml2::XMLElement* rotXML = element->FirstChildElement("Rotation");
		Maths::Vector3D position;
		Maths::Vector3D rotation;
		{
			std::stringstream attrib(std::string(posXML->FirstChild()->ToText()->Value()));
			attrib >> position.X() >> position.Y() >> position.Z();
		}
		{
			std::stringstream attrib(std::string(rotXML->FirstChild()->ToText()->Value()));
			attrib >> rotation.X() >> rotation.Y() >> rotation.Z();
		}

		camera->setPosition(position);
		camera->setRotation(rotation);
		
		tinyxml2::XMLElement* nearXML = element->FirstChildElement("Near");
		tinyxml2::XMLElement* farXML = element->FirstChildElement("Far");
		
		{
			std::stringstream attrib(std::string(nearXML->FirstChild()->ToText()->Value()));
			attrib >> camera->Near();
		}
		{
			std::stringstream attrib(std::string(farXML->FirstChild()->ToText()->Value()));
			attrib >> camera->Far();
		}

		if (isPerspective)
		{
			camera->setProjection();
			tinyxml2::XMLElement* fovyXML = element->FirstChildElement("Fovy");
			float aspect = Renderer->getWindowWidth()/(float)(Renderer->getWindowHeight());

			{
				std::stringstream attrib(std::string(fovyXML->FirstChild()->ToText()->Value()));
				attrib >> camera->Fovy();
			}
			camera->Aspect() = aspect;
		} else 
		{
			camera->setOrtho();
			tinyxml2::XMLElement* topXML = element->FirstChildElement("Top");
			tinyxml2::XMLElement* bottomXML = element->FirstChildElement("Bottom");
			tinyxml2::XMLElement* rightXML = element->FirstChildElement("Right");
			tinyxml2::XMLElement* leftXML = element->FirstChildElement("Left");
			
			{
				std::stringstream attrib(std::string(topXML->FirstChild()->ToText()->Value()));
				attrib >> camera->Top();
			}
			{
				std::stringstream attrib(std::string(bottomXML->FirstChild()->ToText()->Value()));
				attrib >> camera->Bottom();
			}
			{
				std::stringstream attrib(std::string(leftXML->FirstChild()->ToText()->Value()));
				attrib >> camera->Left();
			}
			{
				std::stringstream attrib(std::string(rightXML->FirstChild()->ToText()->Value()));
				attrib >> camera->Right();
			}
		}
	} 
	else if (type == "Entity")
	{
		HashedString name(element->Attribute("Name"));
		HashedString component(element->Attribute("Component"));
		Entity::Map_t::iterator entity = m_entities.find(name);
		if (component == OrientationComponent::type)
		{
			OrientationComponent* orientation = (OrientationComponent*)(entity->second->FindComponent(OrientationComponent::type));
			workingNode->Push_Back(orientation->getTransformNode());
			thisNode = orientation->getTransformNode();
		} else if (component == GraphicalComponent::type)
		{
			GraphicalComponent* graphic = (GraphicalComponent*)(entity->second->FindComponent(GraphicalComponent::type));
			workingNode->Push_Back(graphic->getNode());
			thisNode = graphic->getNode();
		}
	}
	else if (type == "LightNode")
	{
		LightNode* lightNode = new LightNode();
		Light& light = lightNode->getLight();

		tinyxml2::XMLElement* posXML = element->FirstChildElement("Position");
		tinyxml2::XMLElement* ambientXML = element->FirstChildElement("Ambient");
		tinyxml2::XMLElement* diffuseXML = element->FirstChildElement("Diffuse");
		tinyxml2::XMLElement* specularXML = element->FirstChildElement("Specular");
		tinyxml2::XMLElement* spotDirXML = element->FirstChildElement("SpotDirection");
		tinyxml2::XMLElement* spotExpoXML = element->FirstChildElement("SpotExponent");
		tinyxml2::XMLElement* spotCutOffXML = element->FirstChildElement("SpotCutOff");
		tinyxml2::XMLElement* constAttenXML = element->FirstChildElement("ConstAttenuation");
		tinyxml2::XMLElement* linAttenXML = element->FirstChildElement("LinearAttenuation");
		tinyxml2::XMLElement* quadAttenXML = element->FirstChildElement("QuadraticAttenuation");
		
		{
			std::string test(posXML->FirstChild()->ToText()->Value());
			std::stringstream attrib(test);
			for (int i = 0; i < 4; ++i)
				attrib >> light.m_Position[i];
		}
		{
			std::stringstream attrib(std::string(ambientXML->FirstChild()->ToText()->Value()));
			for (int i = 0; i < 4; ++i)
				attrib >> light.m_Ambient[i];
		}
		{
			std::stringstream attrib(std::string(diffuseXML->FirstChild()->ToText()->Value()));
			for (int i = 0; i < 4; ++i)
				attrib >> light.m_Diffuse[i];
		}
		{
			std::stringstream attrib(std::string(specularXML->FirstChild()->ToText()->Value()));
			for (int i = 0; i < 4; ++i)
				attrib >> light.m_Specular[i];
		}
		{
			std::stringstream attrib(std::string(spotDirXML->FirstChild()->ToText()->Value()));
			for (int i = 0; i < 3; ++i)
				attrib >> light.m_SpotDirection[i];
		}
		{
			std::stringstream attrib(std::string(spotExpoXML->FirstChild()->ToText()->Value()));
			attrib >> light.m_SpotExponent;
		}
		{
			std::stringstream attrib(std::string(spotCutOffXML->FirstChild()->ToText()->Value()));
			attrib >> light.m_SpotCutOff;
		}
		{
			std::stringstream attrib(std::string(constAttenXML->FirstChild()->ToText()->Value()));
			attrib >> light.m_ConstAttenuation;
		}
		{
			std::stringstream attrib(std::string(linAttenXML->FirstChild()->ToText()->Value()));
			attrib >> light.m_LinearAttenuation;
		}
		{
			std::stringstream attrib(std::string(quadAttenXML->FirstChild()->ToText()->Value()));
			attrib >> light.m_QuadraticAttenuation;
		}
		workingNode->Push_Back(Pointer<INode>(lightNode));
		thisNode = lightNode;
	}
	for (tinyxml2::XMLElement* node = element->FirstChildElement("Node"); node != NULL; node = node->NextSiblingElement("Node"))
	{
		LoadNode(thisNode, node);
	}
	return true;
}
bool EditorGameState::LoadState( std::string filename )
{
	tinyxml2::XMLDocument doc;
	doc.LoadFile(filename.c_str());

	tinyxml2::XMLElement* rootNode = doc.RootElement();
	// Load Textures

	tinyxml2::XMLElement* textureList = rootNode->FirstChildElement("TextureList");

	if (textureList)
	{
		for (tinyxml2::XMLElement* texture = textureList->FirstChildElement("Texture"); texture != NULL; texture = texture->NextSiblingElement())
		{
			std::string filename = texture->Attribute("Filename");
			LoadTexture(filename);
		}
	}

	// Load resources
	tinyxml2::XMLElement* resourceList = rootNode->FirstChildElement("ResourceList");
	LoadResources(resourceList);
	// Load Entities
	tinyxml2::XMLElement* entityList = rootNode->FirstChildElement("EntityList");
	LoadEntities(entityList);
	// Load SceneGraph
	tinyxml2::XMLElement* sceneGraph = rootNode->FirstChildElement("SceneGraph");
	LoadSceneGraph(sceneGraph);
	return true;
}